package dynamicproxy;

import java.lang.reflect.Proxy;
import java.util.HashMap;

public class HRMTest {

	// Create a HashMap to store employee object as a name value pair
	HashMap<String, Developer> developer = new HashMap<String, Developer>();

	public HRMTest() {
		// Constructor creates a new Developer by giving it a few properties.
		Developer dinesh = new DeveloperImpl();
		dinesh.setName("Dinesh Varyani");
		dinesh.setSalary("25000");
		dinesh.setRating(7);
		dinesh.setRole("Senior Developer");
		developer.put("Dinesh", dinesh);

	}

	public static void main(String[] args) {

		// main method after creating HRMTest object calls test() method.
		HRMTest hrmTest = new HRMTest();
		hrmTest.test();

	}

	public void test() {

		// Initially if Proxy Design Pattern hadn't been implemented Developer
		// and Manager can all change state of Developer/employee properties.
		System.out.println("------------------------------------------------");
		System.out.println("Let's test Developer perspective .....\n");

		// Lets look at developer perspective what he has restriction on him 
		// after implementing Proxy Design pattern.
		Developer dinesh = (Developer) developer.get("Dinesh");
		Developer developerProxy = getDeveloperProxy(dinesh);

		System.out.println("Name of the developer : " + developerProxy.getName());

		// He cannot set his rating, salary and role. An exception will be
		// thrown which will print following message in sysouts
		try {
			developerProxy.setRating(10);
		} catch (Exception e) {
			System.out.println("Developer cant provide rating to itself");
		}

		try {
			developerProxy.setSalary("100000");
		} catch (Exception e) {
			System.out.println("Developer increase or set salary to itself");
		}

		try {
			developerProxy.setRole("Manager");
		} catch (Exception e) {
			System.out.println("Developer cannot change its role in company\n");
		}

		System.out.println("-------------------------------------------------");

		System.out.println("Let's test Managers perspective .....\n");

		// Lets look at the Managers perspective now as what it does to developer object
		dinesh = (Developer) developer.get("Dinesh");

		Developer managerProxy = getManagerProxy(dinesh);

		System.out.println("Name of the developer : " + managerProxy.getName());

		System.out.println("Set salary of the employee : ");
		managerProxy.setSalary("15000");

		System.out.println("Salary of the developer : "+ managerProxy.getSalary());

		// He cannot change the name of the developer. Rest he can change i.e
		// salary, role and rating.
		try {
			managerProxy.setName("Mangesh Virani");
		} catch (Exception e) {
			System.out.println("Manager cant change or set name of developer");
		}

		System.out.println("--------------------------------------------");

	}

	// In order to create Dynamic Proxy we have to apply following steps in java
	// This method takes in a Developer object (real) and returns back the proxy 
	// for it. It returns a Developer which acts as proxy.
	public Developer getDeveloperProxy(Developer employee) {

		// To create a Dynamic Proxy we have to call newProxyInstance() 
		// static method of class Proxy.
		// It takes three arguments :
		// 1. Class Loader for our real object.
		// 2. Set of interfaces proxy needs to implement.
		// 3. A new object of our DeveloperHandling invocation
		// handler. It takes in the real object and returns
		// us back with proxy object.

		return (Developer) Proxy.newProxyInstance(employee.getClass().getClassLoader(), 
				employee.getClass().getInterfaces(),
				new DeveloperHandling(employee));

	}

	public Developer getManagerProxy(Developer employee) {
		// Same as above. Instead of Developer now it returns
		// an proxy on Managers Handling mechanism.
		return (Developer) Proxy.newProxyInstance(employee.getClass().getClassLoader(), 
				employee.getClass().getInterfaces(),
				new ManagersHandling(employee));

	}

}